package com.hy.exception;

import com.hy.base.RestError;
import org.apache.http.HttpStatus;
import org.apache.log4j.Logger;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Set;

/**
 * Created by hy on 2017/7/15.
 */
@ControllerAdvice
public class ExceptionHandlerBase {
    protected Logger logger = Logger.getLogger(this.getClass());
    private static StringWriter sw = new StringWriter();
    private static PrintWriter writer = new PrintWriter(sw);

    @ExceptionHandler(IOException.class)
    @ResponseBody
    public RestError handleIOException(IOException ex, HttpServletResponse response) throws Exception {
        response.setStatus(HttpStatus.SC_BAD_REQUEST);
        RestError error = new RestError();
        error.setMessage("IO操作异常");
        sw = new StringWriter();
        writer = new PrintWriter(sw);
        ex.printStackTrace(writer);
        error.setStackTraceMessage(sw.toString());
        error.setCode(0);
        return error;
    }


    /**
     * 用于捕获JSR303 验证时的错误
     * 将 BindException输出为可为REST api理解的形式
     *
     * @param ex
     * @return
     * @throws Exception
     */
//    @ExceptionHandler(BindException.class)
//    @ResponseBody
//    public RestError handleBindException(BindException ex, HttpServletResponse response) throws Exception {
//        if (ex.hasErrors()) {
//            List<ParameterError> errors = new ArrayList<ParameterError>();
//            for (FieldError fieldError : ex.getFieldErrors()) {
//                ParameterError parameterError = new ParameterError(fieldError.getField(), fieldError.getDefaultMessage());
//                errors.add(parameterError);
//            }
//            response.setStatus(HttpStatus.SC_BAD_REQUEST);
//            RestError error = new RestError();
//            error.setMessage(errors.get(0).getError());
//            error.setDeveloperMessage(errors);
//            error.setCode(0);
//            return error;
//        }
//        return null;
//    }

    /**
     * 数据库访问错误
     *
     * @param ex
     * @param response
     * @return
     */
    @ExceptionHandler(SQLException.class)
    @ResponseBody
    public RestError handleSQLException(SQLException ex, HttpServletResponse response) {
        response.setStatus(HttpStatus.SC_BAD_REQUEST);
        RestError error = new RestError();
        error.setMessage("database access error");
        error.setStackTraceMessage(ex.getMessage());
        error.setCode(0);
        logger.error(ex.getMessage(), ex);
        return error;
    }

//    /**
//     * API 接口异常类的基类处理方法
//     * 所有可抛出的异常必须继承于 RestErrorException
//     *
//     * @param ex       RestErrorException的继承类
//     * @param response HttpServletResponse
//     * @throws Exception
//     */
//    @ExceptionHandler(RestErrorException.class)
//    @ResponseBody
//    public RestError handleRestException(RestErrorException ex, HttpServletResponse response) {
//        response.setStatus(HttpStatus.SC_BAD_REQUEST);
//        RestError error = new RestError();
//        error.setCode(ex.getCode());
//        if (ex.getDeveloperMessage() != null) {
//            error.setDeveloperMessage(ex.getDeveloperMessage());
//        }
//        if (ex.getMessages() != null) {
//            error.setMessage(ex.getMessages());
//        }
//        if (ex.getMoreInfoUrl() != null) {
//            error.setMoreInfoUrl(ex.getMoreInfoUrl());
//        }
//        logger.error(ex.getMessage(),ex);
//        return error;
//    }

    /**
     * 服务异常
     *
     * @param ex
     * @param response
     * @return
     */
    @ExceptionHandler(ServiceException.class)
    @ResponseBody
    public RestError handleServiceException(ServiceException ex, HttpServletResponse response) {
        response.setStatus(HttpStatus.SC_BAD_REQUEST);
        RestError error = new RestError();
        error.setCode(ex.getCode());
        sw = new StringWriter();
        writer = new PrintWriter(sw);
        ex.printStackTrace(writer);
        error.setStackTraceMessage(sw.toString());
        if (ex.getMessage() != null) {
            error.setMessage(ex.getMessage());
        }
        logger.error(ex.getMessage(),ex);
        return error;
    }

//    /**
//     * Spring Security 权限异常
//     *
//     * @param ex
//     * @param response
//     * @return
//     */
//    @ExceptionHandler(AccessDeniedException.class)
//    @ResponseBody
//    public RestError handleAccessDeniedException(AccessDeniedException ex, HttpServletResponse response) {
//        response.setStatus(HttpStatus.SC_FORBIDDEN);
//        RestError error = new RestError();
//        error.setCode(HttpStatus.SC_FORBIDDEN);
//        error.setMessage(ex.getMessage());
//        logger.error(ex.getMessage(),ex);
//        return error;
//    }

    /**
     * 处理内部异常，记录日志
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    public RestError handleRuntimException(RuntimeException ex, HttpServletRequest request, HttpServletResponse response) {
        response.setStatus(HttpStatus.SC_BAD_REQUEST);
        RestError error = new RestError();
        error.setCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
        error.setMessage("服务器运行异常" + ex.getMessage());
        sw = new StringWriter();
        writer = new PrintWriter(sw);
        ex.printStackTrace(writer);
        error.setStackTraceMessage(sw.toString());
        logger.error(ex.getMessage(),ex);
        return error;
    }

    @ExceptionHandler(ValidationException.class)
    @ResponseBody
    public RestError handleValidationException(ValidationException ex, HttpServletResponse response) {
        response.setStatus(HttpStatus.SC_BAD_REQUEST);
        RestError error = new RestError();
        error.setCode(HttpStatus.SC_BAD_REQUEST);
        error.setMessage("参数异常：" + ex.getMessage());
        sw = new StringWriter();
        writer = new PrintWriter(sw);
        ex.printStackTrace(writer);
        error.setStackTraceMessage(sw.toString());
        if (ex instanceof ConstraintViolationException) {
            Set<ConstraintViolation<?>> violations =((ConstraintViolationException) ex).getConstraintViolations();
            Iterator iterator = violations.iterator();
            while (iterator.hasNext()) {
                ConstraintViolation violation = (ConstraintViolation)iterator.next();
                error.setMessage("参数异常：" + violation.getMessage());
            }
        }
        logger.error(ex.getMessage(),ex);
        return error;
    }

    /**
     * 处理内部异常，记录日志
     *
     * @param ex
     * @param response
     * @return
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public RestError handleException(Exception ex, HttpServletResponse response) {
        response.setStatus(HttpStatus.SC_BAD_REQUEST);
        RestError error = new RestError();
        error.setCode(500);
        error.setMessage("服务器异常");
        sw = new StringWriter();
        writer = new PrintWriter(sw);
        ex.printStackTrace(writer);
        error.setStackTraceMessage(sw.toString());
        logger.error(ex.toString(), ex);
        return error;
    }

}
